<!DOCTYPE HTML>
<html>
<head>
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
</head>
<body>
<script>

// Formatting of promises is done according to
// https://www.chromium.org/blink/serviceworker/testing#TOC-Layout-Tests-Style

promise_test(function() {
  return navigator.mediaDevices.getUserMedia({})
    .then(function(s) {
        assert_unreached('getUserMedia should have failed');
      })
    .catch(function(e) {
        assert_equals(e.name, 'TypeError');
      });
}, 'getUserMedia() without any media types should fail');

promise_test(function() {
  return navigator.mediaDevices.getUserMedia({'audio': true})
    .then(function(s) {
         // do nothing
      })
    .catch(function(e) {
        assert_unreached('getUserMedia should have succeeded');
      });
}, 'getUserMedia() with audio=true should succeed');

promise_test(function() {
  return navigator.mediaDevices.getUserMedia(
      {audio: {'mandatory': { 'valid_but_unsupported_1': 0}}})
    .then(function(s) {
        assert_unreached('getUserMedia should have failed');
      })
    .catch(function(e) {
        assert_equals(e.name, 'OverconstrainedError');
        assert_equals(e.constraint, 'valid_but_unsupported_1');
      });
}, 'getUserMedia() with unsupported mandatory constraint should fail');

// The next tests document existing behavior. They seem non-conformant
// with the specs.
promise_test(function() {
  return navigator.mediaDevices.getUserMedia({video: {}})
    .then(function(s) {
        assert_unreached('getUserMedia should have failed');
      })
    .catch(function(e) {
        assert_equals(e.name, 'Error');
      });
}, 'getUserMedia() with empty constraints (neither mandatory nor optional) should fail with Error');

// The following set of tests verify behavior when trying to use the
// dictionary form of constraints. The behaviors currently expected are:
// - Unknown names in dictionary: ignored - which means pass
// - Known names and legal syntax for value: pass
// All constraints allow a primitive value (boolean, string or number),
// and Javascript is capable of coercing just about anything into those values,
// so we never get TypeError thrown here.
//
// Tests that the values are parsed and returned correctly are in
// MediaStreamTrack-getConstraints.html.

function check_constraints_fail(name, constraints, expected_error) {
  promise_test(function() {
    return navigator.mediaDevices.getUserMedia({'video': constraints})
      .then(() => assert_unreached('getUserMedia should have failed'),
            e => assert_equals(e.name, expected_error));
  }, name);
}

function check_constraints_pass(name, constraints) {
  promise_test(function() {
    return navigator.mediaDevices.getUserMedia({'video': constraints});
  }, name);
}

check_constraints_pass(
  'Constraint with unsupported name gets ignored',
  {'unsupported_name': 47});

check_constraints_pass(
  'Constraint with exact Long value should be parsed',
  {'height': {exact: 47}});
check_constraints_pass(
  'Constraint with Long naked value should be parsed',
  {height: 47});

check_constraints_pass(
  'echoCancellation constraint with boolean value should be parsed',
  {'echoCancellation': {exact: true}});
check_constraints_pass(
  'echoCancellation constraint with boolean naked value should be parsed',
  {'echoCancellation': true});

check_constraints_pass(
  'autoGainControl constraint with boolean value should be parsed',
  {'autoGainControl': {exact: true}});
check_constraints_pass(
  'autoGainControl constraint with boolean naked value should be parsed',
  {'autoGainControl': true});

check_constraints_pass(
  'noiseSuppression constraint with boolean value should be parsed',
  {'noiseSuppression': {exact: true}});
check_constraints_pass(
  'noiseSuppression constraint with boolean naked value should be parsed',
  {'noiseSuppression': true});

check_constraints_pass(
  'Constraint with string value should work on exact with array',
  {'facingMode': {ideal: ['user']}});

check_constraints_pass(
  'Constraint with exact string value should work',
  {'facingMode': {ideal: 'user'}});

check_constraints_pass(
  'Constraint with naked string value should be parsed',
  {'facingMode': 'user'});

check_constraints_fail(
  'Using both mandatory and height should give TypeError',
  {'mandatory': {'height': '270'}, 'height': '270'}, 'TypeError');

promise_test(async t => {
  let stream = await navigator.mediaDevices.getUserMedia(
    {video: {width: 639, height: 479}});
  let track = stream.getVideoTracks()[0];
  let settings = track.getSettings();
  assert_equals(settings.width, 639);
  assert_equals(settings.height, 479);
  assert_equals(settings.resizeMode, "crop-and-scale");
  track.stop();

  stream = await navigator.mediaDevices.getUserMedia(
    {video: {width: 639, height: 479, resizeMode: {exact: "none"}}});
  track = stream.getVideoTracks()[0];
  settings = track.getSettings();
  // With rescaling disabled, a native resolution is used.
  assert_equals(settings.width, 640);
  assert_equals(settings.height, 480);
  assert_equals(settings.resizeMode, "none");
  track.stop();

  try {
    stream = await navigator.mediaDevices.getUserMedia(
      {video: {width: {exact: 639}, resizeMode: {exact: "none"}}});
    t.add_cleanup(()=>stream.getVideoTracks()[0].stop());
    t.step(() => assert_unreached('applyConstraints should have failed'));
  } catch(e) {
    assert_equals(e.name, 'OverconstrainedError');
    assert_equals(e.constraint, 'width');
  }
}, 'getUserMedia() resizeMode constraint');

</script>
</body>
</html>
